home *** CD-ROM | disk | FTP | other *** search
- /*
- * Objects-in-C object manager
- *
- * Copyright © John Wainwright 1988
- *
- */
-
- #include <stdio.h>
- #include "oic.h"
- #include "generics.h"
- #include "varargs.h"
-
- #define CHECK_OBJS 1 /* turn on or off object checking */
-
- class currentClass; /* class of currently exec'ing method */
- MethodTable *currentGeneric; /* current generic function table */
-
- static int trace; /* trace flag */
- static class trace_class; /* class for class constrained trace */
- static object trace_obj; /* obj for obj constrained trace */
- static int mth_level; /* mth nest level */
- static int class_index; /* class index generator */
-
- /*---------------------------- Class Maker ----------------------------- */
-
- /*
- * create a new class.
- */
- class
- NewClass(ivsize, cvsize, name, va_alist)
- int ivsize, cvsize;
- char *name;
- va_dcl
- {
- va_list pvar;
- register class c;
- register class superclass;
- register classlist **cl;
- register int cvallocz;
- register int nsupers;
- char *strcpy(), *salloc();
-
- c = talloc(struct class);
- c->c_classtag = Class;
- c->c_index = ++class_index;
- c->c_name = strcpy(salloc(strlen(name) + 1), name);
- ivsize = (ivsize + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
- cvsize = (cvsize + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
- c->c_next = classes;
- classes = c;
-
- /* build the supers list */
-
- c->c_ivsize = c->c_cvsize = 0;
- cl = &c->c_superclasses;
- va_start(pvar);
- for (nsupers = 0; (superclass = va_arg(pvar, class)) != END; )
- {
- if (superclass->c_classtag != Class)
- fprintf(stderr, "NewClass (%s): super %d is not a class\n", name, nsupers+1);
- *cl = talloc(classlist);
- (*cl)->cl_class = superclass;
- cl = &(*cl)->cl_next;
- c->c_ivsize += superclass->c_ivsize;
- c->c_cvsize += superclass->c_cvsize;
- nsupers += 1;
- }
-
- if (nsupers == 0) /* inherit, at least, from Object */
- {
- *cl = talloc(classlist);
- (*cl)->cl_class = Object;
- cl = &(*cl)->cl_next;
- }
-
- *cl = END;
-
- /* compute complete object's allocation size */
-
- c->c_ivoffset = c->c_ivsize + sizeof(object);
- c->c_ivsize += ivsize;
- c->c_allocz = c->c_ivsize + sizeof(object);
-
- /*
- * alocate any class variable structure for this class
- */
- c->c_cvoffset = c->c_cvsize;
- c->c_cvsize += cvsize;
- if (c->c_cvsize)
- c->c_classvars = scalloc(c->c_cvsize);
- else
- c->c_classvars = 0;
-
- return c;
- }
-
- int
- IsA(obj, c)
- register object obj;
- register class c;
- {
- return (c == *obj);
- }
-
- int
- IsAKindOf(obj, c)
- register object obj;
- register class c;
- {
- register classlist *cl;
-
- if (c == *obj)
- return 1;
- else
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- if (IsAKindOf(obj, cl->cl_class))
- return 1;
- return 0;
- }
-
- char *
- ClassNameOf(obj)
- object obj;
- {
- return (*obj)->c_name;
- }
-
- int
- IsObj(obj) /* attempts to tell if this is a valid object */
- object obj;
- {
- return (obj != 0 &&
- ((long)obj & ~0x1L) == (long)obj &&
- ((long)obj & 0xFFFFFF) <= (long)ApplLimit &&
- ClassOf(obj) != 0 &&
- ((long)ClassOf(obj) & ~0x1L) == (long)ClassOf(obj) &&
- ((long)ClassOf(obj) & 0xFFFFFF) <= (long)ApplLimit &&
- ClassOf(obj)->c_classtag == Class);
- }
-
- InitOIC()
- {
- /*
- * Bootstrap the Class system...
- * Make initial classes and hand patch those bits that assume
- * they already exist.
- */
- Class = NewClass(sizeof(struct class), 0, "Class", END);
- Class->c_classtag = Class;
- Object = NewClass(0, 0, "Object", END);
- free(Object->c_superclasses);
- Object->c_superclasses = END;
- Class->c_superclasses->cl_class = Object;
- _InitObject();
- _InitClass();
- }
-
- /* ------------------------ Method Tables Manager --------------------- */
-
- /*
- * add methods for a given class to generic function method tables.
- * The class is given followed by a NULL-terminated list of pairs
- * of methodTable & local function addresses.
- */
- AddMethods(c, va_alist)
- class c;
- va_dcl
- {
- va_list pvar;
- register MethodTable *mth;
-
- for (va_start(pvar); (mth = va_arg(pvar, MethodTable *)) != END; )
- {
- if (mth->mth_funcs == 0)
- {
- mth->mth_minClass = c->c_index;
- mth->mth_maxClass = c->c_index;
- mth->mth_funcs = (MethodFunc *)scalloc(sizeof(MethodFunc));
- }
- else if (c->c_index < mth->mth_minClass)
- {
- realloc_funcTable(mth, c->c_index - mth->mth_minClass);
- mth->mth_minClass = c->c_index;
- }
- else if (c->c_index > mth->mth_maxClass)
- {
- realloc_funcTable(mth, c->c_index - mth->mth_maxClass);
- mth->mth_maxClass = c->c_index;
- }
-
- mth->mth_funcs[c->c_index - mth->mth_minClass].mf_func =
- (object (*)())va_arg(pvar, char *);
- mth->mth_funcs[c->c_index - mth->mth_minClass].mf_from = c;
- }
- }
-
- /*
- * add class methods for a given class to generic function method tables.
- */
- AddClassMethods(c, va_alist)
- class c;
- va_dcl
- {
- va_list pvar;
- register MethodTable *mth;
-
- for (va_start(pvar); (mth = va_arg(pvar, MethodTable *)) != END; )
- {
- mth += 1; /* point to class table */
- if (mth->mth_funcs == 0)
- {
- mth->mth_minClass = c->c_index;
- mth->mth_maxClass = c->c_index;
- mth->mth_funcs = (MethodFunc *)scalloc(sizeof(MethodFunc));
- }
- else if (c->c_index < mth->mth_minClass)
- {
- realloc_funcTable(mth, c->c_index - mth->mth_minClass);
- mth->mth_minClass = c->c_index;
- }
- else if (c->c_index > mth->mth_maxClass)
- {
- realloc_funcTable(mth, c->c_index - mth->mth_maxClass);
- mth->mth_maxClass = c->c_index;
- }
-
- mth->mth_funcs[c->c_index - mth->mth_minClass].mf_func =
- (object (*)())va_arg(pvar, char *);
- mth->mth_funcs[c->c_index - mth->mth_minClass].mf_from = c;
- }
- }
-
- /*
- * extend a generic function's method function table.
- * -ve adjustment => add to front, +ve add to end.
- */
- static
- realloc_funcTable(mth, adjustment)
- register MethodTable *mth;
- register int adjustment;
- {
- register int i, n;
- register MethodFunc *funcs;
-
- n = mth->mth_maxClass - mth->mth_minClass + 1;
- funcs = (MethodFunc *)scalloc(sizeof(MethodFunc) * (n + abs(adjustment)));
-
- for (i = 0; i < n; i++)
- funcs[i - ((adjustment < 0) ? adjustment : 0)] = mth->mth_funcs[i];
-
- if (mth->mth_funcs)
- free(mth->mth_funcs);
- mth->mth_funcs = funcs;
- }
-
- char *
- MethodName(mth)
- register MethodTable *mth;
- {
- return mth->mth_name;
- }
-
- /*------------------------ Method Dispatcher -------------------------*/
-
- /* find the method's function
- *
- * does a breadth-first search of the superclass DAG looking for a
- * method function. Caches the function in the local class if inherited.
- */
- static object
- ((*getMethodFunc(c, mth))())
- register class c;
- register MethodTable *mth;
- {
- register classlist *cl;
- register int i;
- register object (*func)();
- register MethodFunc *mf, *smf;
-
- /*
- * check this class
- */
- i = c->c_index - mth->mth_minClass;
- mf = &mth->mth_funcs[i];
- if (i >= 0 && c->c_index <= mth->mth_maxClass &&
- (func = mf->mf_func) != NULL)
- {
- currentClass = mf->mf_from;
- return func;
- }
-
- /*
- * else, check immediate supers in breadth-first search
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- {
- i = cl->cl_class->c_index - mth->mth_minClass;
- smf = &mth->mth_funcs[i];
- if (i >= 0 && cl->cl_class->c_index <= mth->mth_maxClass &&
- (func = smf->mf_func) != NULL)
- {
- /*
- * inherited, cache it in the local class's method table
- */
- AddMethods(c, mth, func, NULL);
- currentClass =
- mth->mth_funcs[cl->cl_class->c_index - mth->mth_minClass].mf_from;
- mth->mth_funcs[c->c_index - mth->mth_minClass].mf_from =
- currentClass;
- return func;
- }
- }
-
- /*
- * else, recurse down the superclass DAG
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- if ((func = getMethodFunc(cl->cl_class, mth)) != NULL)
- {
- AddMethods(c, mth, func, NULL);
- mth->mth_funcs[c->c_index - mth->mth_minClass].mf_from =
- currentClass;
- return func;
- }
-
- return NULL;
- }
-
- /*
- * dispatch a generic's method function.
- *
- * also keeps track of the class in which this current method was found.
- */
- object
- Method(mth, obj, args)
- register MethodTable *mth;
- register object obj;
- char *args;
- {
- register object (*func)();
- class saveCurrentClass;
- MethodTable *saveCurrentGeneric;
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- fprintf(stderr, "** method (%s) to non-object (%lx)\n", mth->mth_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- saveCurrentGeneric = currentGeneric;
- if ((func = getMethodFunc(*obj, mth)) != NULL)
- {
- if (trace)
- traceMethod(mth, obj);
- mth_level += 1;
- currentGeneric = mth;
- obj = (*func)(obj, &((char *)obj)[currentClass->c_ivoffset], args);
-
- mth_level -= 1;
- currentClass = saveCurrentClass;
- currentGeneric = saveCurrentGeneric;
-
- return obj;
- }
-
- fprintf(stderr, "** No \"%s\" method for %s\n", mth->mth_name, ClassNameOf(obj));
- }
-
- /*
- * dispatch a generic's class method function.
- *
- * given the class method function table. calls the function with class
- * and local class variable structure as the 1st 2 args.
- *
- * if a class method is not found, attempts to invoke the generic as a
- * normal method on class 'class'.
- *
- * this function, which could have been integrated with 'Method', is a
- * separate function in the interests of efficiency.
- */
- object
- ClassMethod(mth, c, args)
- register MethodTable *mth;
- register class c;
- char *args;
- {
- register object (*func)();
- register object obj;
- class saveCurrentClass;
- MethodTable *saveCurrentGeneric;
-
- #ifdef CHECK_OBJS
- if (c->c_classtag != Class)
- {
- fprintf(stderr, "** class method (%s) to non-class (%lx)\n", mth->mth_name, c);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- saveCurrentGeneric = currentGeneric;
- if ((func = getMethodFunc(c, mth)) != NULL)
- {
- if (trace)
- traceClassMethod(mth, c);
- mth_level += 1;
-
- currentGeneric = mth;
- obj = (*func)(c, &(c->c_classvars)[currentClass->c_cvoffset], args);
-
- mth_level -= 1;
- currentClass = saveCurrentClass;
- currentGeneric = saveCurrentGeneric;
-
- return obj;
- }
- else
- return Method(&mth[-1], c, args);
-
- fprintf(stderr, "** No \"%s\" class method for %s\n", mth->mth_name, c->c_name);
- }
-
- /*
- * called by Super to find the method definition next up the superclass
- * DAG from the current method's class.
- *
- * does a breadth-first search of the superclass DAG looking for the
- * method function inherited from the supers further than 'currentClass'.
- *
- * this function, a slight variant of 'getMethodFunc', is a
- * separate function in the interests of efficiency.
- */
- static object
- ((*getSuperMethodFunc(c, mth, beyond))())
- register class c;
- register MethodTable *mth;
- int beyond;
- {
- register classlist *cl;
- register int i;
- register object (*func)();
- register MethodFunc *mf, *smf;
-
- /*
- * check this class
- */
- i = c->c_index - mth->mth_minClass;
- mf = &mth->mth_funcs[i];
-
- if (mf->mf_from == currentClass)
- beyond = 1;
-
- if (beyond &&
- mf->mf_from != currentClass && /* ignore current method's class */
- i >= 0 && c->c_index <= mth->mth_maxClass &&
- (func = mf->mf_func) != NULL)
- {
- currentClass = mf->mf_from;
- return func;
- }
-
- /*
- * else, check immediate supers in breadth-first search
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- {
- i = cl->cl_class->c_index - mth->mth_minClass;
- smf = &mth->mth_funcs[i];
-
- if (smf->mf_from == currentClass)
- beyond = 1;
-
- if (beyond &&
- smf->mf_from != currentClass &&
- i >= 0 && cl->cl_class->c_index <= mth->mth_maxClass &&
- (func = smf->mf_func) != NULL)
- {
- currentClass = smf->mf_from;
- return func;
- }
- }
-
- /*
- * else, recurse down the superclass DAG
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- if ((func = getSuperMethodFunc(cl->cl_class, mth, beyond)) != NULL)
- return func;
-
- return NULL;
- }
-
- object
- Super(obj, args)
- object obj;
- char *args;
- {
- register object (*func)();
- class saveCurrentClass;
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- fprintf(stderr, "** super method (%s) on non-object (%lx)\n", currentGeneric->mth_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- if ((func = getSuperMethodFunc(*obj, currentGeneric, 0)) != NULL)
- {
- if (trace)
- traceSuperMethod(currentGeneric, obj);
- mth_level += 1;
-
- obj = (*func)(obj, &((char *)obj)[currentClass->c_ivoffset], &args);
-
- mth_level -= 1;
- currentClass = saveCurrentClass;
-
- return obj;
- }
-
- fprintf(stderr, "** No \"%s\" super method for %s\n", currentGeneric->mth_name, ClassNameOf(obj));
- }
-
- /*
- * Identical to 'Super', above, except that a pointer to the argument
- * list is given instead of them being in place.
- *
- * This allows methods to easily pass their arguments up to the super
- * they are invoking (e.g., see 'new' in IndexMixin).
- *
- * Like other variant functions, it is a separate function in the
- * interests of efficiency.
- */
- object
- SuperPassArgs(obj, argp)
- object obj;
- char **argp;
- {
- register object (*func)();
- class saveCurrentClass;
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- fprintf(stderr, "** super method (%s) on non-object (%lx)\n", currentGeneric->mth_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- if ((func = getSuperMethodFunc(*obj, currentGeneric, 0)) != NULL)
- {
- if (trace)
- traceSuperMethod(currentGeneric, obj);
- mth_level += 1;
-
- obj = (*func)(obj, &((char *)obj)[currentClass->c_ivoffset], argp);
-
- mth_level -= 1;
- currentClass = saveCurrentClass;
-
- return obj;
- }
-
- fprintf(stderr, "** No \"%s\" super method for %s\n", currentGeneric->mth_name, ClassNameOf(obj));
- }
-
- /*---------------------------- Object Maker -----------------------------*/
-
- /*
- * creates a new instance of the given class. Inits all instance vars to
- * zero, and sends 'new' to it.
- */
- object
- New(c, args)
- register class c;
- char *args;
- {
- register object obj;
- register char *p;
-
- obj = (object)scalloc(c->c_allocz);
- *obj = c;
- Method(newGeneric, obj, &args); /* send it the 'new' message */
-
- return obj;
- }
-
- int
- SizeOf(obj)
- object obj;
- {
- return ClassOf(obj)->c_allocz;
- }
-
-
- static
- traceMethod(mth, obj)
- MethodTable *mth;
- object obj;
- {
- if (trace_class == NULL || *obj == trace_class &&
- trace_obj == NULL || obj == trace_obj)
- {
- fprintf(stderr, "%.*s%s ", mth_level,
- mth_level ? ".............." : "", MethodName(mth));
- if (ClassOf(obj) != currentClass)
- fprintf(stderr, "(from %s) ", currentClass->c_name);
- fprintf(stderr, "on %s @%lx\n", ClassNameOf(obj), obj);
- }
- }
-
- static
- traceClassMethod(mth, c)
- MethodTable *mth;
- object c;
- {
- if (trace_class == NULL || ClassOf(c) == trace_class &&
- trace_obj == NULL || c == trace_obj)
- {
- fprintf(stderr, "%.*s%s ", mth_level,
- mth_level ? ".............." : "", MethodName(mth));
- if ((class)c != currentClass)
- fprintf(stderr, "(from %s) ", currentClass->c_name);
- fprintf(stderr, "on class %s @%lx\n", ((class)c)->c_name, c);
- }
- }
-
- static
- traceSuperMethod(mth, obj)
- MethodTable *mth;
- object obj;
- {
- if (trace_class == NULL || *obj == trace_class &&
- trace_obj == NULL || obj == trace_obj)
- {
- fprintf(stderr, "%.*ssuper %s ", mth_level,
- mth_level ? ".........." : "", MethodName(mth));
- if (ClassOf(obj) != currentClass)
- fprintf(stderr, "(from %s) ", currentClass->c_name);
- fprintf(stderr, "on %s @%lx\n", ClassNameOf(obj), obj);
- }
- }
-
- TraceOn()
- {
- trace = 1;
- }
-
- TraceOff()
- {
- trace = 0;
- trace_obj = NULL;
- trace_class = NULL;
- }
-
- TraceObj(obj)
- object obj;
- {
- trace = 1;
- trace_obj = obj;
- }
-
- TraceClass(c)
- class c;
- {
- trace = 1;
- trace_class = c;
- }
-
- dumpClass(c)
- register class c;
- {
- register classlist *cl;
-
- fprintf(stderr, "Class \"%s\" :\n", c->c_name);
- fprintf(stderr, " supers : (");
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- fprintf(stderr, "%s%s", cl->cl_class->c_name, (cl->cl_next) ? "," : "");
- fprintf(stderr, ")\n index %d\n cv\'s %lx, offset %d\n", c->c_index,
- c->c_classvars, c->c_cvoffset);
- }
-
- dumpMethodTable(mth)
- register MethodTable *mth;
- {
- register int i, l;
-
- fprintf(stderr, "\"%s\" method table : \n", mth->mth_name);
- fprintf(stderr, " class indexes : low %d, high %d\n", (l = mth->mth_minClass), mth->mth_maxClass);
- for (i = l; i <= mth->mth_maxClass; i++)
- if (mth->mth_funcs[i - l].mf_func)
- fprintf(stderr, " (%d) fn %lx from %s\n",
- i, mth->mth_funcs[i - l].mf_func,
- (mth->mth_funcs[i - l].mf_from)->c_name);
- }
-
- object
- key_arg(arglist, key, default_arg)
- register keyword_args arglist;
- int key;
- object default_arg;
- {
- for (; *(int *)arglist != key && *(int *)arglist != 0; arglist += sizeof(int) + sizeof(long))
- ;
- if (*(int *)arglist == 0)
- return default_arg;
- else
- return *(object *)(arglist + sizeof(int));
- }
-